1. Field
The disclosed embodiments generally relate to computer systems that support multi-threaded programming. More specifically, the disclosed embodiments relate to a method and an apparatus for implementing a notification barrier, wherein a call to the notification barrier does not return until an associated sender object has no currently pending notifications for a receiver object.
2. Related Art
Object-oriented programming environments often provide a notification system to support sending notifications between objects. For example, a sender object (associated with an audio device) can use a notification system to post a notification to a receiver object (associated with a synthesizer), wherein the notification requests that the synthesizer send more audio data to the audio device.
During construction of an object tree for an application, the notification system can be used to specify that one object sends notifications to another object. For example, a callback can be installed on a sender object to send notifications to a receiver object. (The callback could be a function pointer or closure implemented by the receiver object, or a reference to the receiver object along with an agreed object method that can be called.) Afterward, when the receiver object is no longer needed, the system tears down the receiver object, and also removes the callback from the sender object. However, when this callback is removed from the sender object, there is an inherent race condition between removing the callback and the callback firing. This can create problems because a callback may be called on another thread asynchronously from the “tear down thread” which is performing the teardown. In this case, it is possible for the other thread to begin issuing the callback just before the callback is removed by the tear down thread. As a consequence, after the tear down thread removes the callback, the system has no way of knowing whether the callback is still running on another asynchronous thread. Moreover, if the receiver object is being torn down and its memory is being reclaimed, at some point it may no longer be safe for the callback to execute.
One solution to this problem involves taking a lock while removing the callback, wherein the lock is also taken whenever the callback is called. In this way, it is not possible to remove the callback and to call the callback at the same time. However, if this solution is used, the callback cannot remove itself (which is a desirable way to express a teardown) because doing so can cause a deadlock.
Another solution is let the notification receiver deal with the problem. In this case, the notification receiver needs to leave something around that lasts indefinitely to handle a potential notification. This involves abandoning some memory to handle the fact the callback might get called later on. Because the time window for receiving a callback later on is likely to be small, it is undesirable to abandon memory indefinitely for this purpose.
There are other techniques. For example, if it is possible to control which thread the notification will be posted on, the system can arrange to do the callback removal on the same thread. However, this is a fairly strict programming constraint in a multi-threaded system, which may be impractical for many multi-threaded applications.
Hence, what is needed is an efficient technique for solving the problem of eliminating race conditions while removing a callback.